/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Eclipse Public License (EPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/eclipse-1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm.compilers.opt.depgraph;

import org.jikesrvm.compilers.opt.ir.operand.Operand;
import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
import org.jikesrvm.compilers.opt.util.SpaceEffGraphEdge;

/**
 * Dependence graph edges: connect operands of different instructions
 * represented by dependence graph nodes.
 */
public final class DepGraphEdge extends SpaceEffGraphEdge implements DepGraphConstants {
  /**
   * Does this edge represent a register true dependence?
   * @return true if yes, false otherwise
   */
  public boolean isRegTrue() { return (scratch & REG_TRUE) != 0; }

  /**
   * Does this edge represent a register anti-dependence?
   * @return true if yes, false otherwise
   */
  public boolean isRegAnti() { return (scratch & REG_ANTI) != 0; }

  /**
   * Does this edge represent a register output dependence?
   * @return true if yes, false otherwise
   */
  public boolean isRegOutput() { return (scratch & REG_OUTPUT) != 0; }

  /**
   * Does this edge represent a register may def?
   * @return true if yes, false otherwise
   */
  public boolean isRegMayDef() { return (scratch & REG_MAY_DEF) != 0; }

  /**
   * Does this edge represent a memory true dependence?
   * @return true if yes, false otherwise
   */
  public boolean isMemTrue() { return (scratch & MEM_TRUE) != 0; }

  /**
   * Does this edge represent a memory anti-dependence?
   * @return true if yes, false otherwise
   */
  public boolean isMemAnti() { return (scratch & MEM_ANTI) != 0; }

  /**
   * Does this edge represent a memory output dependence?
   * @return true if yes, false otherwise
   */
  public boolean isMemOutput() { return (scratch & MEM_OUTPUT) != 0; }

  /**
   * Does this edge represent a memory reads-kill dependence?
   * @return true if yes, false otherwise
   */
  public boolean isMemReadsKill() { return (scratch & MEM_READS_KILL) != 0; }

  /**
   * Does this edge represent a control dependence?
   * @return true if yes, false otherwise
   */
  public boolean isControl() { return (scratch & CONTROL) != 0; }

  /**
   * Does this edge represent an exception-exception dependence?
   * @return true if yes, false otherwise
   */
  public boolean isExceptionE() { return (scratch & EXCEPTION_E) != 0; }

  /**
   * Does this edge represent an exception-store dependence?
   * @return true if yes, false otherwise
   */
  public boolean isExceptionMS() { return (scratch & EXCEPTION_MS) != 0; }

  /**
   * Does this edge represent an exception-load dependence?
   * @return true if yes, false otherwise
   */
  public boolean isExceptionML() { return (scratch & EXCEPTION_ML) != 0; }

  /**
   * Does this edge represent an exception-register live dependence?
   * @return true if yes, false otherwise
   */
  public boolean isExceptionR() { return (scratch & EXCEPTION_R) != 0; }

  /**
   * Does this edge represent a guard true dependence?
   * @return true if yes, false otherwise
   */
  public boolean isGuardTrue() { return (scratch & GUARD_TRUE) != 0; }

  /**
   * Does this edge represent a guard anti-dependence?
   * @return true if yes, false otherwise
   */
  public boolean isGuardAnti() { return (scratch & GUARD_ANTI) != 0; }

  /**
   * Does this edge represent a guard output dependence?
   * @return true if yes, false otherwise
   */
  public boolean isGuardOutput() { return (scratch & GUARD_OUTPUT) != 0; }

  /**
   * Does a given edge represent a register true dependence?
   * Use to avoid a cast from SpaceEffGraphEdge to DepGraphEdge.
   * @param edge the edge to test
   * @return true if yes, false otherwise
   */
  public static boolean isRegTrue(SpaceEffGraphEdge edge) {
    return (edge.getInfo() & REG_TRUE) != 0;
  }

  /**
   * Does a given edge represent a register anti-dependence?
   * Use to avoid a cast from SpaceEffGraphEdge to DepGraphEdge.
   * @param edge the edge to test
   * @return true if yes, false otherwise
   */
  public static boolean isRegAnti(SpaceEffGraphEdge edge) {
    return (edge.getInfo() & REG_ANTI) != 0;
  }

  /**
   * Does a given edge represent a register output dependence?
   * Use to avoid a cast from SpaceEffGraphEdge to DepGraphEdge.
   * @param edge the edge to test
   * @return true if yes, false otherwise
   */
  public static boolean isRegOutput(SpaceEffGraphEdge edge) {
    return (edge.getInfo() & REG_OUTPUT) != 0;
  }

  /**
   * The destination operand (of a REG_TRUE dependence)
   */
  private RegisterOperand _destOperand;

  /**
   * Augment the type of the dependence edge.
   * @param type the additional type for the edge
   */
  void addDepType(int type) { scratch |= type; }

  /**
   * @param sourceNode source dependence graph node
   * @param destNode destination dependence graph node
   * @param depKind the type of the dependence edge
   */
  DepGraphEdge(DepGraphNode sourceNode, DepGraphNode destNode, int depKind) {
    this(null, sourceNode, destNode, depKind);
  }

  /**
   * Constructor for dependence graph edge of a REG_TRUE dependence
   * from sourceNode to destNode due to destOp
   * @param destOp destination operand
   * @param sourceNode source dependence graph node
   * @param destNode destination dependence graph node
   * @param depKind the type of the dependence edge
   */
  DepGraphEdge(RegisterOperand destOp, DepGraphNode sourceNode, DepGraphNode destNode, int depKind) {
    super(sourceNode, destNode);
    _destOperand = destOp;
    setInfo(depKind);
  }

  /**
   * Get the type of the dependence edge.
   * @return type of the dependence edge
   */
  int depKind() {
    return getInfo();
  }

  /**
   * Get the destination operand.
   * @return destination operand
   */
  RegisterOperand destOperand() {
    return _destOperand;
  }

  /**
   * Get the string representation of edge type (used for printing).
   * @return string representation of edge type
   */
  public String getTypeString() {
    String result = "";
    if (isRegTrue()) {
      result += " REG_TRUE ";
    }
    if (isRegAnti()) {
      result += " REG_ANTI ";
    }
    if (isRegOutput()) {
      result += " REG_OUT  ";
    }
    if (isMemTrue()) {
      result += " MEM_TRUE ";
    }
    if (isMemAnti()) {
      result += " MEM_ANTI ";
    }
    if (isMemOutput()) {
      result += " MEM_OUT  ";
    }
    if (isMemReadsKill()) {
      result += " MEM_READS_KILL  ";
    }
    if (isControl()) {
      result += " CONTROL  ";
    }
    if (isExceptionE()) {
      result += " EXCEP_E  ";
    }
    if (isExceptionMS()) {
      result += " EXCEP_MS ";
    }
    if (isExceptionML()) {
      result += " EXCEP_ML ";
    }
    if (isExceptionR()) {
      result += " EXCEP_R  ";
    }
    if (isGuardTrue()) {
      result += " GUARD_TRUE ";
    }
    if (isGuardAnti()) {
      result += " GUARD_ANTI ";
    }
    if (isGuardOutput()) {
      result += " GUARD_OUT  ";
    }
    if (isRegMayDef()) {
      result += " REG_MAY_DEF";
    }
    return result;
  }

  /**
   * Returns the string representation of the edge.
   * @return string representation of the edge
   */
  public String toString() {
    return _fromNode + " ---> " + _toNode + getTypeString();
  }

  /**
   * Returns the string representation of the end node (used for printing).
   * @return string representation of the end node
   * @see SpaceEffGraphEdge#toNodeString()
   */
  public String toNodeString() {
    return getTypeString() + " " + _toNode;
  }

  /**
   * Returns the string representation of the start node (used for printing).
   * @return string representation of the start node
   * @see SpaceEffGraphEdge#fromNodeString()
   */
  public String fromNodeString() {
    return getTypeString() + " " + _fromNode;
  }

  /**
   * Return the input edge for a given node that corresponds to a given operand.
   * @param n destination node
   * @param op destination operand
   * @return input edge or null if not found
   */
  public static DepGraphEdge findInputEdge(DepGraphNode n, Operand op) {
    for (DepGraphEdge inEdge = (DepGraphEdge) n.firstInEdge(); inEdge != null; inEdge =
        (DepGraphEdge) inEdge.getNextIn()) {
      if (inEdge.destOperand() == op) {
        return inEdge;
      }
    }
    return null; // edge not found
  }
}



